package com.aco.fatureapp.service;

import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import android.database.sqlite.SQLiteDatabase;
import android.util.Log;
import br.com.ac.fatureweb.integration.billing.FaturaVO;
import br.com.ac.fatureweb.integration.billing.LancamentoCobradoVO;
import br.com.ac.fatureweb.integration.billing.ProdutoVO;
import br.com.ac.fatureweb.integration.billing.ValorVO;
import br.com.ac.fatureweb.integration.business.GerarFatura;
import br.com.ac.fatureweb.integration.model.ConfiguracaoCalculoVO;
import br.com.ac.fatureweb.integration.model.ConfiguracaoSaaeVO;
import br.com.ac.fatureweb.integration.model.EconomiaVO;
import br.com.ac.fatureweb.integration.model.FaixaVO;
import br.com.ac.fatureweb.integration.model.ImovelVO;
import br.com.ac.fatureweb.integration.model.LancamentoFuturoVO;
import br.com.ac.fatureweb.integration.model.MensagemVO;
import br.com.ac.fatureweb.integration.model.OcorrenciaVO;
import br.com.ac.fatureweb.integration.model.SaldoDebitoCreditoVO;
import br.com.ac.fatureweb.integration.model.TarifaSocialVO;
import br.com.ac.fatureweb.integration.model.TarifaVO;
import br.com.ac.fatureweb.integration.utilitary.NumberUtils;

import com.aco.fatureapp.activity.MeteringActivity.LeituraValidator;
import com.aco.fatureapp.auxiliary.ShowBillItem;
import com.aco.fatureapp.model.AnaliseAgua;
import com.aco.fatureapp.model.ConfiguracaoCalculo;
import com.aco.fatureapp.model.ConfiguracaoSaae;
import com.aco.fatureapp.model.Economia;
import com.aco.fatureapp.model.Faixa;
import com.aco.fatureapp.model.Historico;
import com.aco.fatureapp.model.Imovel;
import com.aco.fatureapp.model.LancamentoFuturo;
import com.aco.fatureapp.model.Leiturista;
import com.aco.fatureapp.model.Mensagem;
import com.aco.fatureapp.model.Ocorrencia;
import com.aco.fatureapp.model.ProductDetail;
import com.aco.fatureapp.model.Roteiro;
import com.aco.fatureapp.model.SaldoDebitoCredito;
import com.aco.fatureapp.model.Tarifa;
import com.aco.fatureapp.model.TarifaSocial;
import com.aco.fatureapp.model.billing.Conta;
import com.aco.fatureapp.model.billing.Fatura;
import com.aco.fatureapp.model.billing.LancamentoCobrado;
import com.aco.fatureapp.model.billing.LogCorrecaoConta;
import com.aco.fatureapp.model.billing.LogLeitura;
import com.aco.fatureapp.model.billing.Produto;
import com.aco.fatureapp.model.billing.Produto.EnumTypeProduto;
import com.aco.fatureapp.model.billing.Valor;
import com.aco.fatureapp.model.billing.Volume;
import com.aco.fatureapp.model.printer.Billing;
import com.aco.fatureapp.model.printer.Historic;
import com.aco.fatureapp.model.printer.Products;
import com.aco.fatureapp.service.exception.BillingException;
import com.aco.fatureapp.utilitary.GpsUtils;
import com.aco.fatureapp.utilitary.Utils;
import com.google.inject.Inject;
import com.orm.SugarApp;
import com.orm.SugarDb;
import com.orm.SugarRecord;
import com.orm.query.Select;

public class SrvBilling {

	private SQLiteDatabase database = null;

	@Inject
	private SrvMetering mSrvMetering;

	@Inject
	public SrvBilling() {
		super();

		database = new SugarDb(SugarApp.getSugarContext())
				.getWritableDatabase();
	}

	public Fatura gerarFatura(LeituraValidator leituraValidator, Imovel entity,
			GpsUtils gpsUtils, Long idLeiturista, boolean impressoraDesativada)
			throws BillingException {
		try {
			Long inscricao = entity.getInscricao();

			Long dataLeitura = new Date().getTime();

			ImovelVO imovelVo = Imovel.parseImovelVo(entity);

			ConfiguracaoCalculoVO configuracaoCalculo = getConfiguracaoCalculo();

			FaturaVO faturaVO = new GerarFatura().gerar(
					leituraValidator.leitura, dataLeitura,
					leituraValidator.codOcorrencia, 100L,
					entity.getLeituraAnterior(), imovelVo, configuracaoCalculo,
					getConfiguracaoSaae(), getLstOcorrencia(), getLstTarifa(),
					getLstFaixa(), getLstTarifaSocial(inscricao),
					getLstMensagem(), getLstEconomia(inscricao),
					getLstLancamentoFuturo(inscricao),
					getLstSaldoDebitoCreditoVO(inscricao));

			Conta conta = new Conta(faturaVO.getConta());
			conta.save();

			List<LancamentoCobradoVO> lstLancamento = faturaVO
					.getLstLancamento();

			LogLeitura logLeitura = gerarLogLeitura(leituraValidator, entity,
					gpsUtils, dataLeitura, conta);

			logLeitura.setIdLeiturista(idLeiturista);
			logLeitura.setValorConta(conta.getValorConta());
			logLeitura.setValorTotal(conta.getValorConta());

			List<LancamentoCobrado> lstLancamentoCobrado = new ArrayList<LancamentoCobrado>();

			if (lstLancamento != null && !lstLancamento.isEmpty()) {
				Double total = 0D;

				for (LancamentoCobradoVO lancamentoVo : lstLancamento) {

					LancamentoCobrado lancamentoCobrado = new LancamentoCobrado(
							lancamentoVo);

					total += lancamentoVo.getValor();

					lstLancamentoCobrado.add(lancamentoCobrado);

					lancamentoCobrado.save();
				}

				logLeitura.setValorServicos(total);
			}

			List<ProdutoVO> lstProduto = faturaVO.getLstProduto();

			List<Produto> lstProdutoG = new ArrayList<Produto>();

			Volume volumeImpressao = null;

			if (lstProduto != null && !lstProduto.isEmpty()) {
				for (ProdutoVO produtoVo : lstProduto) {

					Produto produto = new Produto(produtoVo);

					lstProdutoG.add(produto);

					produto.save();

					EnumTypeProduto enumTypeProduto = EnumTypeProduto
							.valueOf(produtoVo.getCodigo());

					switch (enumTypeProduto) {
					case AGUA: {
						logLeitura.setValorAgua(produtoVo.getValor());
						break;
					}
					case ESGOTO: {
						logLeitura.setValorEsgoto(produtoVo.getValor());
						break;
					}
					}

					if (produtoVo.getVolumeVO() != null) {
						Volume volume = new Volume(produtoVo.getVolumeVO());
						volumeImpressao = volume;

						volume.save();
					}

					List<ValorVO> lstValorVO = produtoVo.getLstValorVO();

					if (lstValorVO != null && !lstValorVO.isEmpty()) {
						for (ValorVO valorVO : lstValorVO) {
							Valor valor = new Valor(valorVO);

							valor.save();
						}
					}
				}
			}

			logLeitura.setMes(entity.getMes().longValue());
			logLeitura.setAno(entity.getAno().longValue());

			final String[] param = { inscricao.toString() };

			List<LogCorrecaoConta> lstCorrecao = Select
					.from(LogCorrecaoConta.class).where("INSCRICAO = ?", param)
					.list();
			if (lstCorrecao != null && !lstCorrecao.isEmpty()) {
				logLeitura.setQtdeCorrecao(Integer.valueOf(lstCorrecao.size())
						.longValue());

				logLeitura.setQtdeImpressao(logLeitura.getQtdeImpressao());

				logLeitura.setContaRegerada(true);
			}

			logLeitura.setFlgEnvioAutomatico(false);
			logLeitura.setPrintResumo(false);

			Leiturista leiturista = Leiturista.findById(Leiturista.class,
					idLeiturista);

			logLeitura.setIdLeiturista(leiturista.getIdIntegracao());

			// Se a leitura for nula, colocar a leitura anterior.
			if (logLeitura.getLeitura() == null) {
				logLeitura.setLeitura(imovelVo.getLeituraAnterior());

				if (logLeitura.getLeitura() == null) {
					logLeitura.setLeitura(0L);
				}
			}

			logLeitura.setConsumo(volumeImpressao.getConsumoFaturado());

			logLeitura.save();

			List<Economia> lstEconomia = Select.from(Economia.class)
					.where("INSCRICAO = ?", param).list();

			Fatura fatura = new Fatura(logLeitura, null);

			if (!impressoraDesativada) {
				if (isEmitirConta(inscricao)) {

					Billing billing = gerarImpressao(configuracaoCalculo,
							conta, logLeitura, lstLancamentoCobrado,
							lstProdutoG, volumeImpressao, param, idLeiturista,
							lstEconomia);

					fatura.setBilling(billing);
				}
			}

			return fatura;
		}
		catch (Exception ex) {
			if (ex instanceof NullPointerException) {
				Log.e("Erro de nullpointer", "erro de nullpointer");
			}
			else {
				Log.e("Geracao_conta", ex.getMessage());
			}
			throw new BillingException(ex);
		}
	}

	public Integer getQuantidadeEconomia(Long codInscricao) {
		String[] param = { codInscricao.toString() };

		List<Economia> lstEconomia = Select.from(Economia.class)
				.where("INSCRICAO = ?", param).list();

		return somarEconomias(lstEconomia);
	}

	private Billing gerarImpressao(ConfiguracaoCalculoVO configuracaoCalculo,
			Conta conta, LogLeitura logLeitura,
			List<LancamentoCobrado> lstLancamentoCobrado,
			List<Produto> lstProdutoG, Volume volumeImpressao,
			final String[] param, Long idLeiturista, List<Economia> lstEconomia) {
		Imovel imovel = Select.from(Imovel.class).where("INSCRICAO = ?", param)
				.first();

		Tarifa tarifa = Select
				.from(Tarifa.class)
				.where("CODIGO = ?",
						new String[] { imovel.getTarifa().toString() }).first();

		AnaliseAgua analiseAgua = Select.from(AnaliseAgua.class).first();

		Historico historico = Select.from(Historico.class)
				.where("INSCRICAO = ?", param).first();

		Ocorrencia ocorrencia = Select
				.from(Ocorrencia.class)
				.where("CODIGO = ?",
						new String[] { logLeitura.getCodOcorrencia1()
								.toString() }).first();

		Integer qtdEconomia = somarEconomias(lstEconomia);

		Billing billing = getBilling(imovel, conta, tarifa, volumeImpressao,
				analiseAgua, lstProdutoG, lstLancamentoCobrado, historico,
				configuracaoCalculo, logLeitura, ocorrencia, idLeiturista,
				qtdEconomia);

		return billing;
	}

	private LogLeitura gerarLogLeitura(LeituraValidator leituraValidator,
			Imovel entity, GpsUtils gpsUtils, Long dataLeitura, Conta conta) {
		Double latitude = null;
		Double longitude = null;

		if (gpsUtils.getLatitude() != 0) {
			latitude = NumberUtils.truncateValue(gpsUtils.getLatitude(),
					NumberUtils.TypeDecimal.SEVEN_DECIMAL);
		}

		if (gpsUtils.getLongitude() != 0) {
			longitude = NumberUtils.truncateValue(gpsUtils.getLongitude(),
					NumberUtils.TypeDecimal.SEVEN_DECIMAL);
		}

		LogLeitura logLeitura = new LogLeitura(leituraValidator.leitura,
				dataLeitura, conta.getValorConta(), 0L, 0L, false,
				leituraValidator.codOcorrencia, 100L, entity.getInscricao(),
				entity.getIdCarga(), "", null, conta.getTypeRetencao(), false,
				false, longitude, latitude);

		return logLeitura;
	}

	public ConfiguracaoSaaeVO getConfiguracaoSaae() {
		final Iterator<ConfiguracaoSaae> lstConfiguracaoSaae = SugarRecord
				.findAll(ConfiguracaoSaae.class);

		if (lstConfiguracaoSaae != null && lstConfiguracaoSaae.hasNext()) {

			ConfiguracaoSaae configuracaoSaae = lstConfiguracaoSaae.next();

			ConfiguracaoSaaeVO configuracaoSaaeVO = new ConfiguracaoSaaeVO(
					configuracaoSaae.getIdIntegracao(),
					configuracaoSaae.getCidCliente(),
					configuracaoSaae.getUnfCliente(),
					configuracaoSaae.getSiglaCliente(),
					configuracaoSaae.getDataRemessa(),
					configuracaoSaae.getHoraRemessa(),
					configuracaoSaae.isExibirLeituraAnterior(),
					configuracaoSaae.isExibirOcorrenciaAnterior(),
					configuracaoSaae.getFatConszerado(),
					configuracaoSaae.getPercentualVariacaoLeitura(),
					configuracaoSaae.isOcultaCsmsemhidro());

			return configuracaoSaaeVO;
		}

		return null;
	}

	public ConfiguracaoCalculoVO getConfiguracaoCalculo() {
		final Iterator<ConfiguracaoCalculo> lstConfiguracaoCalculo = SugarRecord
				.findAll(ConfiguracaoCalculo.class);

		if (lstConfiguracaoCalculo != null && lstConfiguracaoCalculo.hasNext()) {

			ConfiguracaoCalculo configuracaoCalculo = lstConfiguracaoCalculo
					.next();

			ConfiguracaoCalculoVO configuracaoCalculoVO = new ConfiguracaoCalculoVO(
					configuracaoCalculo.getIdIntegracao(),
					configuracaoCalculo.getPctMulta(),
					configuracaoCalculo.getPctJuros(),
					configuracaoCalculo.getValMinimo(),
					configuracaoCalculo.getFlgConshidro(),
					configuracaoCalculo.getCsmConshidro(),
					configuracaoCalculo.getDesConshidro(),
					configuracaoCalculo.getValConshidro(),
					configuracaoCalculo.getFlgTaxa1(),
					configuracaoCalculo.getCsmTaxa1(),
					configuracaoCalculo.getDesTaxa1(),
					configuracaoCalculo.getValTaxa1(),
					configuracaoCalculo.getFlgTaxa2(),
					configuracaoCalculo.getCsmTaxa2(),
					configuracaoCalculo.getDesTaxa2(),
					configuracaoCalculo.getValTaxa2());

			return configuracaoCalculoVO;
		}

		return null;
	}

	public List<SaldoDebitoCreditoVO> getLstSaldoDebitoCreditoVO(
			final Long inscricao) {
		final String[] param = { inscricao.toString() };

		final List<SaldoDebitoCredito> lstSaldoDebitoCredito = Select
				.from(SaldoDebitoCredito.class).where("INSCRICAO = ?", param)
				.list();

		if (lstSaldoDebitoCredito != null && !lstSaldoDebitoCredito.isEmpty()) {

			final List<SaldoDebitoCreditoVO> lstRetorno = new ArrayList<SaldoDebitoCreditoVO>();

			for (final SaldoDebitoCredito saldoDebitoCredito : lstSaldoDebitoCredito) {

				final SaldoDebitoCreditoVO debitoCreditoVO = new SaldoDebitoCreditoVO(
						saldoDebitoCredito.getIdIntegracao(),
						saldoDebitoCredito.getInscricao(),
						saldoDebitoCredito.getTipo(),
						saldoDebitoCredito.getConsumo());

				lstRetorno.add(debitoCreditoVO);
			}

			return lstRetorno;
		}

		return null;
	}

	public List<OcorrenciaVO> getLstOcorrencia() {
		final Iterator<Ocorrencia> lstAllOcorrencia = SugarRecord
				.findAll(Ocorrencia.class);

		if (lstAllOcorrencia != null && lstAllOcorrencia.hasNext()) {
			final List<OcorrenciaVO> lstRetorno = new ArrayList<OcorrenciaVO>();

			while (lstAllOcorrencia.hasNext()) {
				final Ocorrencia ocorrencia = lstAllOcorrencia.next();

				final OcorrenciaVO ocorrenciaVO = new OcorrenciaVO(
						ocorrencia.getIdIntegracao(), ocorrencia.getCodigo(),
						ocorrencia.getDescricao(),
						ocorrencia.isFlgOcorrencia(),
						ocorrencia.getFlgTipoCobranca(),
						ocorrencia.isFlgEmitirConta());

				lstRetorno.add(ocorrenciaVO);
			}

			return lstRetorno;
		}

		return null;
	}

	public List<TarifaVO> getLstTarifa() {
		final Iterator<Tarifa> lstAllTarifa = SugarRecord.findAll(Tarifa.class);

		if (lstAllTarifa != null && lstAllTarifa.hasNext()) {
			final List<TarifaVO> lstRetorno = new ArrayList<TarifaVO>();

			while (lstAllTarifa.hasNext()) {
				final Tarifa tarifa = lstAllTarifa.next();

				TarifaVO tarifaVO = new TarifaVO(tarifa.getIdIntegracao(),
						tarifa.getCodigo(), tarifa.getAno(), tarifa.getMes(),
						tarifa.getValorFixo(), tarifa.getValorSemhidro(),
						tarifa.getSigla());

				lstRetorno.add(tarifaVO);
			}

			return lstRetorno;
		}

		return null;
	}

	public List<FaixaVO> getLstFaixa() {
		final Iterator<Faixa> lstAllFaixa = SugarRecord.findAll(Faixa.class);

		if (lstAllFaixa != null && lstAllFaixa.hasNext()) {
			final List<FaixaVO> lstRetorno = new ArrayList<FaixaVO>();

			while (lstAllFaixa.hasNext()) {
				final Faixa faixa = lstAllFaixa.next();

				FaixaVO faixaVO = new FaixaVO(faixa.getIdIntegracao(),
						faixa.getInicio(), faixa.getFim(), faixa.getValor(),
						faixa.isCobrancaMaxima(), faixa.getCodTarifa());

				lstRetorno.add(faixaVO);
			}

			return lstRetorno;
		}

		return null;
	}

	public List<TarifaSocialVO> getLstTarifaSocial(final Long inscricao) {
		final String[] param = { inscricao.toString() };

		final List<TarifaSocial> lstTarifaSocial = Select
				.from(TarifaSocial.class).where("INSCRICAO = ?", param).list();

		if (lstTarifaSocial != null && !lstTarifaSocial.isEmpty()) {

			List<TarifaSocialVO> lstRetorno = new ArrayList<TarifaSocialVO>();

			for (final TarifaSocial tarifaSocial : lstTarifaSocial) {

				TarifaSocialVO tarifaSocialVO = new TarifaSocialVO(
						tarifaSocial.getIdIntegracao(),
						tarifaSocial.getInscricao(),
						tarifaSocial.getConsumoMinimo(),
						tarifaSocial.getCodigoTarifaSocial());

				lstRetorno.add(tarifaSocialVO);
			}

			return lstRetorno;
		}

		return null;
	}

	public List<EconomiaVO> getLstEconomia(final Long inscricao) {
		final String[] param = { inscricao.toString() };

		final List<Economia> lstEconomia = Select.from(Economia.class)
				.where("INSCRICAO = ?", param).list();

		if (lstEconomia != null && !lstEconomia.isEmpty()) {

			final List<EconomiaVO> lstRetorno = new ArrayList<EconomiaVO>();

			for (final Economia economia : lstEconomia) {

				EconomiaVO economiaVO = new EconomiaVO(
						economia.getIdIntegracao(), economia.getInscricao(),
						economia.getCodTarifa(), economia.getQtdEconomias());

				lstRetorno.add(economiaVO);
			}

			return lstRetorno;
		}

		return null;
	}

	public List<MensagemVO> getLstMensagem() {
		final Iterator<Mensagem> lstAllMensagem = SugarRecord
				.findAll(Mensagem.class);

		if (lstAllMensagem != null && lstAllMensagem.hasNext()) {
			final List<MensagemVO> lstRetorno = new ArrayList<MensagemVO>();

			while (lstAllMensagem.hasNext()) {
				final Mensagem mensagem = lstAllMensagem.next();

				MensagemVO mensagemVO = new MensagemVO(
						mensagem.getIdIntegracao(), mensagem.getTipMensagem(),
						mensagem.getCodigo(), mensagem.getLinha1(),
						mensagem.getLinha2(), mensagem.getLinha3(),
						mensagem.getLinha4(), mensagem.getLinha5(),
						mensagem.getLinha6(), mensagem.getLinha7(),
						mensagem.getLinha8());

				lstRetorno.add(mensagemVO);
			}

			return lstRetorno;
		}

		return null;
	}

	public List<LancamentoFuturoVO> getLstLancamentoFuturo(final Long inscricao) {
		final String[] param = { inscricao.toString() };

		final List<LancamentoFuturo> lstLancamentoFuturo = Select
				.from(LancamentoFuturo.class).where("INSCRICAO = ?", param)
				.list();

		if (lstLancamentoFuturo != null && !lstLancamentoFuturo.isEmpty()) {

			final List<LancamentoFuturoVO> lstRetorno = new ArrayList<LancamentoFuturoVO>();

			for (final LancamentoFuturo lancamento : lstLancamentoFuturo) {

				LancamentoFuturoVO lancamentoVO = new LancamentoFuturoVO(
						lancamento.getIdIntegracao(),
						lancamento.getInscricao(), lancamento.getCodServico(),
						lancamento.getDescricao(), lancamento.getValor(),
						lancamento.getParcela());

				lstRetorno.add(lancamentoVO);
			}

			return lstRetorno;
		}

		return null;
	}

	/**
	 *
	 * Busca a lista de lançamento cobrados de uma determinada inscrição e
	 * retorna em um formato definido para ser exibido em uma tela de detalhe
	 * como um item de uma fatura.
	 *
	 * @param inscricao
	 * @return
	 */
	public List<ShowBillItem> getLstLancamentoCobrado(final Long inscricao) {
		final List<ShowBillItem> lstRetorno = new ArrayList<ShowBillItem>();
		final String[] param = { inscricao.toString() };

		final List<LancamentoCobrado> lstLancamentoCobrado = Select
				.from(LancamentoCobrado.class).where("INSCRICAO = ?", param)
				.list();

		if (lstLancamentoCobrado != null && !lstLancamentoCobrado.isEmpty()) {

			for (final LancamentoCobrado lancamento : lstLancamentoCobrado) {

				ShowBillItem lstBillItem = new ShowBillItem(
						lancamento.getDescricao(), lancamento.getParcela(),
						lancamento.getValor());

				lstRetorno.add(lstBillItem);
			}
		}

		return lstRetorno;
	}

	/**
	 *
	 * Busca a lista de produtos de uma determinada inscrição e retorna em um
	 * formato definido para ser exibido em uma tela de detalhe como um item de
	 * uma fatura.
	 *
	 * @param inscricao
	 * @return
	 */
	public List<ShowBillItem> getLstProduto(final Long inscricao) {
		final List<ShowBillItem> lstRetorno = new ArrayList<ShowBillItem>();
		final String[] param = { inscricao.toString() };

		final List<Produto> lstProduto = Select.from(Produto.class)
				.where("INSCRICAO = ?", param).list();

		if (lstProduto != null && !lstProduto.isEmpty()) {

			for (final Produto produto : lstProduto) {

				ShowBillItem lstBillItem = new ShowBillItem(
						produto.getDescricao(), "-", produto.getValor(),
						produto.getCodigo());

				lstRetorno.add(lstBillItem);
			}
		}

		return lstRetorno;
	}

	/**
	 *
	 * @param mInscricao
	 * @param codigo
	 * @return
	 */
	public List<ProductDetail> getLstProductDetail(Long inscricao,
			ShowBillItem produto) {
		final List<ProductDetail> lstRetorno = new ArrayList<ProductDetail>();
		final String[] param = { inscricao.toString(),
				EnumTypeProduto.valueOf(produto.getCodigo()).ordinal() + "" };

		final List<Volume> lstVolume = Select.from(Volume.class)
				.where("INSCRICAO = ? AND COD_PRODUTO = ?", param).list();

		ProductDetail detail = new ProductDetail(produto.getCodigo().toString()
				+ " - " + produto.getDescricao(), produto.getValor());

		if (lstVolume != null && !lstVolume.isEmpty()) {

			for (final Volume volume : lstVolume) {
				detail.vlrConsumoAgua = volume.getConsumoAguaMes() != null ? volume
						.getConsumoAguaMes() : 0L;

				detail.vlrConsumoMedido = volume.getConsumoMedido() != null ? volume
						.getConsumoMedido() : 0L;

				detail.vlrConsumoFaturado = volume.getConsumoFaturado() != null ? volume
						.getConsumoFaturado() : 0l;

				detail.vlrLeituraAnterior = volume.getLeituraAnterior() != null ? volume
						.getLeituraAnterior() : 0l;

				detail.vlrLeituraAtual = volume.getLeituraAtual() != null ? volume
						.getLeituraAtual() : 0l;

				if (volume.getCodOcorrencia1() != null) {
					detail.dscOcorrencia = mSrvMetering
							.getDescricaoOcorrencia(volume.getCodOcorrencia1());
				}
			}
		}

		lstRetorno.add(detail);

		return lstRetorno;
	}

	/**
	 * Método responsável por fechar a conexão com a base de dados.
	 */
	public void closeDB() {
		database.close();
	}

	public LogLeitura getLogLeitura(Long inscricao) {
		final String[] param = { inscricao.toString() };

		LogLeitura logLeitura = Select.from(LogLeitura.class)
				.where("INSCRICAO = ?", param).first();

		return logLeitura;
	}

	public Billing getFaturaImpressao(Long inscricao, Long idLeiturista) {

		final String[] param = { inscricao.toString() };

		Imovel imovel = Select.from(Imovel.class).where("INSCRICAO = ?", param)
				.first();

		Conta conta = Select.from(Conta.class).where("INSCRICAO = ?", param)
				.first();

		List<Economia> lstEconomia = Select.from(Economia.class)
				.where("INSCRICAO = ?", param).list();

		Tarifa tarifa = Select
				.from(Tarifa.class)
				.where("CODIGO = ?",
						new String[] { imovel.getTarifa().toString() }).first();

		Volume volume = Select.from(Volume.class).where("INSCRICAO = ?", param)
				.first();

		AnaliseAgua analiseAgua = Select.from(AnaliseAgua.class).first();

		List<Produto> lstProduto = Select.from(Produto.class)
				.where("INSCRICAO = ?", param).list();

		List<LancamentoCobrado> lstLancamentoCobrado = Select
				.from(LancamentoCobrado.class).where("INSCRICAO = ?", param)
				.list();

		Historico historico = Select.from(Historico.class)
				.where("INSCRICAO = ?", param).first();

		ConfiguracaoCalculoVO configuracaoCalculo = getConfiguracaoCalculo();

		LogLeitura logLeitura = getLogLeitura(inscricao);

		Ocorrencia ocorrencia = Select
				.from(Ocorrencia.class)
				.where("CODIGO = ?",
						new String[] { logLeitura.getCodOcorrencia1()
								.toString() }).first();

		if (idLeiturista == null) {
			Leiturista leiturista = Select
					.from(Leiturista.class)
					.where("ID_INTEGRACAO = ?",
							new String[] { logLeitura.getIdLeiturista()
									.toString() }).first();

			idLeiturista = leiturista.getId();
		}

		Integer qtdEconomia = somarEconomias(lstEconomia);

		Billing billing = getBilling(imovel, conta, tarifa, volume,
				analiseAgua, lstProduto, lstLancamentoCobrado, historico,
				configuracaoCalculo, logLeitura, ocorrencia, idLeiturista,
				qtdEconomia);

		return billing;
	}

	private Integer somarEconomias(List<Economia> lstEconomia) {
		Integer qtdEconomia = 1;

		if (lstEconomia != null && !lstEconomia.isEmpty()) {
			for (Economia economia : lstEconomia) {
				qtdEconomia += economia.getQtdEconomias();
			}
		}
		return qtdEconomia;
	}

	private Billing getBilling(Imovel imovel, Conta conta, Tarifa tarifa,
			Volume volume, AnaliseAgua analiseAgua, List<Produto> lstProduto,
			List<LancamentoCobrado> lstLancamentoCobrado, Historico historico,
			ConfiguracaoCalculoVO configuracaoCalculo, LogLeitura logLeitura,
			Ocorrencia ocorrencia, Long idLeiturista, Integer qtdEconomia) {

		String inscricaoTemp = imovel.getInscricao().toString();

		String inscricaoFormat = inscricaoTemp.substring(0,
				inscricaoTemp.length() - 1)
				+ "-" + inscricaoTemp.substring(inscricaoTemp.length() - 1);

		Long dataProximaLeitura = imovel.getDataProximaLeitura();

		String localizacao = "0000"
				+ Utils.formartZeroLeft(imovel.getCodSetor(), 2)
				+ Utils.formartZeroLeft(imovel.getOrdemRoteiro(), 4);

		String numeroFatura = "";

		if (imovel.getNumeroFatura() != null) {
			numeroFatura = imovel.getNumeroFatura();
		}

		Billing billing = new Billing(inscricaoFormat,

		localizacao,

		Utils.formartZeroLeft(imovel.getMes(), 2) + "/" + imovel.getAno(),

		imovel.getNomeResponsavel(),

		imovel.getEndereco2(),

		imovel.getBairro(),

		imovel.getCidade(),

		imovel.getUf(), "    ",

		imovel.getClasse().toString(), "0",

		tarifa.getSigla(), qtdEconomia.toString(),

		imovel.getNumeroHidrometro(),

		Utils.dateFormat(imovel.getDataLeituraAnterior()),

		Utils.dateFormat(imovel.getDataInstalacaoHidrometro()),

		Utils.dateFormat(logLeitura.getDataLeitura()),

		imovel.getLeituraAnterior().toString(),

		Utils.dateFormat(dataProximaLeitura),

		logLeitura.getLeitura() != null ? logLeitura.getLeitura().toString()
				: " ",

		volume != null && volume.getDiasConsumo() != null ? volume
				.getDiasConsumo().toString() : " ",

		volume != null && volume.getConsumoFaturado() != null ? volume
				.getConsumoFaturado().toString() : " ",

		ocorrencia.getDescricao(),

		conta.getMensagem1(), conta.getMensagem2(),

		conta.getMensagem3(),

		conta.getMensagem4(),

		Utils.dateFormat(imovel.getDataVencimento()),

		Utils.formatValue(conta.getValorConta()),

		Utils.formatValue(configuracaoCalculo.getPctMulta()), "0,00",

		Utils.formatValue(configuracaoCalculo.getPctJuros()),

		conta.getCodigoBarra1() + conta.getCodigoBarra2()
				+ conta.getCodigoBarra3() + conta.getCodigoBarra4(),
				Utils.formartZeroLeft(logLeitura.getIdLeiturista(), 6),
				numeroFatura);

		billing.setMedia(imovel.getConsumoMedio().toString());

		billing.setCodigoBarrasComDigito(conta.getCodigoBarra1() + '-'
				+ conta.getDigitoCodigoBarra1() + " "

				+ conta.getCodigoBarra2() + '-' + conta.getDigitoCodigoBarra2()
				+ " "

				+ conta.getCodigoBarra3() + '-' + conta.getDigitoCodigoBarra3()
				+ " "

				+ conta.getCodigoBarra4() + '-' + conta.getDigitoCodigoBarra4());

		if (imovel.isFlgDebitoEmConta()) {
			billing.setCodigoBarras(null);
			billing.setCodigoBarrasComDigito("CONTA QUITADA");
		}

		billing.setMensagem5(conta.getMensagem5());
		billing.setMensagem6(conta.getMensagem5());

		billing.reservatorio = analiseAgua.getDescricao();
		billing.dataColeta = Utils
				.dateFormat(analiseAgua.getDataColetaInicio());
		billing.reserCampo1 = analiseAgua.getColeta1().toString();
		billing.reserCampo2 = analiseAgua.getColeta2().toString();
		billing.reserCampo3 = analiseAgua.getColeta3().toString();
		billing.reserCampo4 = analiseAgua.getColeta4().toString();
		billing.reserCampo5 = analiseAgua.getColeta5().toString();
		billing.reserCampo6 = analiseAgua.getColeta6().toString();

		List<Products> arrayProducts = new ArrayList<Products>();

		if (lstProduto != null && !lstProduto.isEmpty()) {

			for (Produto produto : lstProduto) {
				Products product = new Products();
				product.codigo = produto.getCodigo().toString();
				product.descricao = produto.getDescricao();
				product.parcela = null;
				product.valor = Utils.formatValue(produto.getValor());

				arrayProducts.add(product);
			}
		}

		if (lstLancamentoCobrado != null && !lstLancamentoCobrado.isEmpty()) {

			for (LancamentoCobrado lancamento : lstLancamentoCobrado) {
				Products product = new Products();
				product.codigo = lancamento.getCodServico().toString();
				product.descricao = lancamento.getDescricao();
				product.parcela = lancamento.getParcela();
				product.valor = Utils.formatValue(lancamento.getValor());

				arrayProducts.add(product);
			}

		}

		billing.setProducts(arrayProducts.toArray(new Products[arrayProducts
				.size()]));

		// Sempre mandar 9 itens, não cabe mais.
		Historic[] historics = new Historic[9];
		historics[0] = new Historic(Utils.formartZeroLeft(historico.getMes1(),
				2) + "/" + historico.getAno1(), historico.getUltimoConsumo1()
				.toString(), historico.getUltimaOcorrencia1().toString());

		historics[1] = new Historic(Utils.formartZeroLeft(historico.getMes2(),
				2) + "/" + historico.getAno2(), historico.getUltimoConsumo2()
				.toString(), historico.getUltimaOcorrencia2().toString());

		historics[2] = new Historic(Utils.formartZeroLeft(historico.getMes3(),
				2) + "/" + historico.getAno3(), historico.getUltimoConsumo3()
				.toString(), historico.getUltimaOcorrencia3().toString());

		historics[3] = new Historic(Utils.formartZeroLeft(historico.getMes4(),
				2) + "/" + historico.getAno4(), historico.getUltimoConsumo4()
				.toString(), historico.getUltimaOcorrencia4().toString());

		historics[4] = new Historic(Utils.formartZeroLeft(historico.getMes5(),
				2) + "/" + historico.getAno5(), historico.getUltimoConsumo5()
				.toString(), historico.getUltimaOcorrencia5().toString());

		historics[5] = new Historic(Utils.formartZeroLeft(historico.getMes6(),
				2) + "/" + historico.getAno6(), historico.getUltimoConsumo6()
				.toString(), historico.getUltimaOcorrencia6().toString());

		for (int index = 1; index <= historics.length; index++) {
			Historic historic = historics[index - 1];

			if (historic == null) {
				historics[index - 1] = new Historic();
			}

		}

		billing.historics = historics;

		return billing;
	}

	/**
	 * Buscar a segunda parte do código de barras.
	 *
	 * @param inscricao
	 * @return
	 */
	public String getCodigoBarra(Long inscricao) {
		final String[] param = { inscricao.toString() };

		Conta conta = Select.from(Conta.class).where("INSCRICAO = ?", param)
				.first();

		return conta.getCodigoBarra2() + conta.getDigitoCodigoBarra2();
	}

	/**
	 * Excluir os dados de uma conta gerada, permitindo a gravação na mesma
	 * novamente.
	 *
	 * @param inscricao
	 * @param idUsuario
	 */
	public void refaturar(Long inscricao, Long idUsuario) {

		final String[] param = { inscricao.toString() };

		Conta conta = Select.from(Conta.class).where("INSCRICAO = ?", param)
				.first();

		Imovel imovel = Select.from(Imovel.class).where("INSCRICAO = ?", param)
				.first();

		LogLeitura logLeitura = Select.from(LogLeitura.class)
				.where("INSCRICAO = ?", param).first();

		List<Volume> lstVolume = Select.from(Volume.class)
				.where("INSCRICAO = ?", param).list();

		Long consumoAgua = null;
		Long consumoEsgoto = null;

		if (lstVolume != null && !lstVolume.isEmpty()) {
			for (Volume volume : lstVolume) {

				EnumTypeProduto enumTypeProduto = EnumTypeProduto
						.valueOfOrdinal(volume.getCodProduto());

				switch (enumTypeProduto) {
				case AGUA: {
					consumoAgua = volume.getConsumoFaturado();
					break;
				}
				case ESGOTO: {
					consumoEsgoto = volume.getConsumoFaturado();
					break;
				}
				}
			}
		}

		LogCorrecaoConta logCorrecaoConta = new LogCorrecaoConta(inscricao,
				conta.getIdCarga(), idUsuario, logLeitura.getIdLeiturista(),
				Long.valueOf(imovel.getAno() + imovel.getMes()),
				conta.getCodigoBarra(), logLeitura.getValorAgua(),
				logLeitura.getValorEsgoto(), logLeitura.getValorConta(),
				logLeitura.getLeitura(), logLeitura.getCodOcorrencia1(),
				logLeitura.getCodOcorrencia2(), consumoAgua, consumoEsgoto,
				logLeitura.getQtdeImpressao(), logLeitura.getContaRetida(),
				new Date().getTime());

		logCorrecaoConta.save();

		conta.delete();
		logLeitura.delete();

		Volume.deleteAll(Volume.class, "INSCRICAO = ?", param);

		LancamentoCobrado.deleteAll(LancamentoCobrado.class, "INSCRICAO = ?",
				param);

		Produto.deleteAll(Produto.class, "INSCRICAO = ?", param);

		Valor.deleteAll(Valor.class, "INSCRICAO = ?", param);
	}

	public Long getDataFaturamento() {
		return Roteiro.listAll(Roteiro.class).iterator().next()
				.getDataFaturamento();
	}

	public boolean isEmitirConta(Long codInscricao) {

		String param[] = { codInscricao.toString() };

		List<Imovel> lstImovel = Imovel.find(Imovel.class, "INSCRICAO =?",
				param);

		if (lstImovel != null && !lstImovel.isEmpty()) {

			Imovel imovel = lstImovel.iterator().next();

			return imovel != null && imovel.isFlgEmitirConta();
		}

		return true;
	}
}
